﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Daybreak.Core.Terrains
{
    public class TerrainTile : IDisposable
    {
        public string TerrainTileFilePath;
        public double TileSizeDegrees;
        public int SamplesPerTile;
        public double South;
        public double North;
        public double West;
        public double East;
        public int Row;
        public int Col;
        public int TargetLevel;
        public TerrainTileService m_owner;
        public bool IsInitialized;
        public bool IsValid;

        public float[,] ElevationData;

        protected ITerrainElevationProvider _provider;

        public TerrainTile(TerrainTileService owner)
        {
            m_owner = owner;
        }
        /// <summary>
        /// This method initializes the terrain tile add switches to
        /// Initialize floating point/int 16 tiles
        /// </summary>
        public void Initialize()
        {
            if (IsInitialized)
                return;

            if (!File.Exists(TerrainTileFilePath))
            {
                // Download elevation
                if (_provider == null)
                {
                    using (_provider = m_owner.GetProvider(Row, Col, TargetLevel))
                    {
                        _provider.ElevateTerrainData(TerrainTileFilePath);
                        //request.SaveFilePath = TerrainTileFilePath;
                        //request.DownloadInForeground();
                    }
                }
            }

            if (ElevationData == null)
                ElevationData = new float[SamplesPerTile, SamplesPerTile];

            _provider.GetElevationData(ElevationData, m_owner);

        }

        public float GetElevationAt(double latitude, double longitude)
        {
            try
            {
                double deltaLat = North - latitude;
                double deltaLon = longitude - West;

                double df2 = (SamplesPerTile - 1) / TileSizeDegrees;
                float lat_pixel = (float)(deltaLat * df2);
                float lon_pixel = (float)(deltaLon * df2);

                int lat_min = (int)lat_pixel;
                int lat_max = (int)Math.Ceiling(lat_pixel);
                int lon_min = (int)lon_pixel;
                int lon_max = (int)Math.Ceiling(lon_pixel);

                if (lat_min >= SamplesPerTile)
                    lat_min = SamplesPerTile - 1;

                if (lat_max >= SamplesPerTile)
                    lat_max = SamplesPerTile - 1;

                if (lon_min >= SamplesPerTile)
                    lon_min = SamplesPerTile - 1;

                if (lon_max >= SamplesPerTile)
                    lon_max = SamplesPerTile - 1;

                if (lat_min < 0)
                    lat_min = 0;
                if (lat_max < 0)
                    lat_max = 0;
                if (lon_min < 0)
                    lon_min = 0;
                if (lon_max < 0)
                    lon_max = 0;

                float delta = lat_pixel - lat_min;
                
                float westElevation =
                    ElevationData[lon_min, lat_min] * (1 - delta) +
                    ElevationData[lon_min, lat_max] * delta;

                float eastElevation =
                    ElevationData[lon_max, lat_min] * (1 - delta) +
                    ElevationData[lon_max, lat_max] * delta;

                delta = lon_pixel - lon_min;

                float interpolatedElevation =
                    westElevation * (1 - delta) +
                    eastElevation * delta;

                return interpolatedElevation;
            }
            catch
            {
            }
            return 0;
        }

        #region IDisposable Members

        public void Dispose()
        {

        }

        #endregion
    }
}
